#include <optix.h>
#include <optixu/optixu_math_namespace.h>
#include "phong.h"

using namespace optix;


rtDeclareVariable(float3, eye, , );
rtDeclareVariable(float3, U, , );
rtDeclareVariable(float3, V, , );
rtDeclareVariable(float3, W, , );
rtDeclareVariable(float3, bad_color, , );
rtBuffer<uchar4, 2>              output_buffer;

rtDeclareVariable(uint2, launch_index, rtLaunchIndex, );
rtDeclareVariable(uint2, launch_dim, rtLaunchDim, );
rtDeclareVariable(float, time_view_scale, , ) = 1e-6f;

//#define TIME_VIEW

RT_PROGRAM void pinhole_camera()
{
#ifdef TIME_VIEW
	clock_t t0 = clock();
#endif
	float2 d = make_float2(launch_index) / make_float2(launch_dim) * 2.f - 1.f;
	float3 ray_origin = eye;
	float3 ray_direction = normalize(d.x*U + d.y*V + W);

	optix::Ray ray = optix::make_Ray(ray_origin, ray_direction, radiance_ray_type, scene_epsilon, RT_DEFAULT_MAX);

	PerRayData_radiance prd;
	prd.importance = 1.f;
	prd.depth = 0;

	rtTrace(top_object, ray, prd);

#ifdef TIME_VIEW
	clock_t t1 = clock();

	float expected_fps = 1.0f;
	float pixel_time = (t1 - t0) * time_view_scale * expected_fps;
	output_buffer[launch_index] = make_color(make_float3(pixel_time));
#else
	output_buffer[launch_index] = make_color(prd.result);
#endif
}

rtDeclareVariable(float3, Ka, , );
rtDeclareVariable(float3, Kd, , );
rtDeclareVariable(float3, Ks, , );
rtDeclareVariable(float3, reflectivity, , );
rtDeclareVariable(float, phong_exp, , );
rtDeclareVariable(float3, bg_color, , );

rtDeclareVariable(float3, geometric_normal, attribute geometric_normal, );
rtDeclareVariable(float3, shading_normal, attribute shading_normal, );

RT_PROGRAM void any_hit_shadow()
{
	phongShadowed();
}


RT_PROGRAM void closest_hit_radiance()
{
	float3 world_shading_normal = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, shading_normal));
	float3 world_geometric_normal = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, geometric_normal));

	float3 ffnormal = faceforward(world_shading_normal, -ray.direction, world_geometric_normal);
	phongShade(Kd, Ka, Ks, ffnormal, phong_exp, reflectivity);
}

RT_PROGRAM void exception()
{
	const unsigned int code = rtGetExceptionCode();
	rtPrintf("Caught exception 0x%X at launch index (%d,%d)\n", code, launch_index.x, launch_index.y);
	output_buffer[launch_index] = make_color(bad_color);
}
rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload, );

RT_PROGRAM void miss()
{
	prd_radiance.result = bg_color;
}
